home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_02_07 / 2n07017b < prev    next >
Text File  |  1991-06-02  |  6KB  |  215 lines

  1. #define TIMER_MIN_RESOLUTION    (55)
  2. #define TIMER_MAX_RESOLUTION    (65535)
  3. #ifdef __cplusplus
  4.     #define OUTOFTIMERS TIMER::OutOfTimers
  5. #else
  6.     #define OUTOFTIMERS OutOfTimers
  7. #endif
  8.  
  9. typedef unsigned long   ulong;
  10. typedef struct TIMERDATA
  11.     {
  12.     FARPROC CallBack;
  13.     TIMER   *TailPtr;
  14.     int     ActiveCount;
  15.     int     TimerId;
  16.     ulong   IntervalGcd;
  17. #ifndef __cplusplus
  18.     TIMER_FIRE  FireFunc;
  19. #endif
  20.     }   TIMERDATA;
  21.  
  22. static TIMERDATA TD;
  23.  
  24.  
  25. ulong    Gcd(ulong a, ulong b)
  26.     {
  27.     ulong    Remainder = a;
  28.  
  29.     if(a==0 || b==0)
  30.         return 0;
  31.     else
  32.         {
  33.         Remainder   = b % a;
  34.         while((Remainder=b%a) != 0)
  35.             {
  36.             b           = a;
  37.             a           = Remainder;
  38.             Remainder   = b % a;
  39.             }
  40.         return a;
  41.         }
  42.     }
  43.  
  44. /*
  45.  *  SetBaseInterval - Change the interval of the
  46.  *      base Window timer.  This function handles
  47.  *      requests that are larger or smaller than
  48.  *      Windows timer resolutions permit.
  49.  */
  50. int     SetBaseInterval(ulong NewInterval)
  51.     {
  52.     if(TD.IntervalGcd != 0)
  53.         NewInterval = Gcd(TD.IntervalGcd, NewInterval);
  54.     if(NewInterval < TIMER_MIN_RESOLUTION)
  55.         NewInterval = TIMER_MIN_RESOLUTION;
  56.     if(NewInterval > TIMER_MAX_RESOLUTION)
  57.         {/* use heuristic to get "nice" interval */
  58.         while(NewInterval > TIMER_MAX_RESOLUTION)
  59.             NewInterval /= 2;
  60.         NewInterval = (NewInterval / 1000) * 1000;
  61.         }
  62.     if(NewInterval != TD.IntervalGcd)
  63.         {
  64.         if(TD.TimerId != 0)
  65.             KillTimer(0, TD.TimerId);
  66.         while((TD.TimerId=SetTimer(0,0,
  67.             (unsigned int)NewInterval,
  68.             TD.CallBack)) == 0)
  69.  
  70.             if(OUTOFTIMERS())
  71.                 break;
  72.         if(TD.TimerId)
  73.             TD.IntervalGcd    = NewInterval;
  74.         else
  75.             return FALSE;
  76.         }
  77.  
  78.     return TRUE;
  79.     }
  80.  
  81. /*
  82.  *  ReviseInterval() - recalculate Gcd of all timers
  83.  *      in circular linked list.
  84.  */
  85. int ReviseInterval()
  86.     {
  87.     TIMER   *Rover = TD.TailPtr;
  88.     ulong   NewInterval = 0;
  89.  
  90.     do  {
  91.         Rover   = Rover->Next;
  92.         if(Rover->Interval != 0)
  93.             if(NewInterval == 0)
  94.                 NewInterval = Rover->Interval;
  95.             else
  96.                 NewInterval = Gcd(NewInterval,
  97.                               Rover->Interval);
  98.         } while(Rover != TD.TailPtr);
  99.     TD.IntervalGcd  = 0;
  100.     return SetBaseInterval(NewInterval);
  101.     }
  102.  
  103. /*
  104.  *  SetInterval() - change the interval of a single
  105.  *     timer.  This may require the base interval
  106.  *     to be changed.  Setting the interval to zero
  107.  *     stops the timer.
  108.  */
  109. int SetInterval(TIMER *Timer, ulong NewInterval)
  110.     {
  111.     ulong   SaveInterval;
  112.     int     TimerWasOn, TimerIsOn, Result;
  113.     Result  = TRUE;     /* Assume success  */
  114.     TimerWasOn  = Timer->Interval != 0;
  115.     TimerIsOn   = NewInterval != 0;
  116.     /* if deactivating timer */
  117.     if(TimerWasOn && !TimerIsOn)
  118.         if(--TD.ActiveCount == 0)
  119.             {
  120.             KillTimer(0, TD.TimerId);
  121.             TD.TimerId      = 0;
  122.             TD.IntervalGcd  = 0;
  123.             }
  124.         else
  125.             Result  = ReviseInterval();
  126.     /* else if starting a timer */
  127.     else if(TimerIsOn && !TimerWasOn)
  128.         {
  129.         Timer->Interval = NewInterval;
  130.         if(NewInterval > TIMER_MAX_RESOLUTION)
  131.             Result  = ReviseInterval();
  132.         else
  133.             Result  = SetBaseInterval(NewInterval);
  134.         if(Result)
  135.             ++TD.ActiveCount;
  136.         }
  137.     /* else if changing timer interval */
  138.     else
  139.         {
  140.         Timer->Interval = NewInterval;
  141.         Result      =ReviseInterval();
  142.         }
  143.     return Result;
  144.     }
  145.  
  146. void    InitTimer(TIMER *Timer, int EventId)
  147.     {
  148.     Timer->EventId  = EventId;
  149.     Timer->Interval = 0;
  150.     Timer->ThisTime = 0;
  151.     Timer->LastTime = 0;
  152.     if(TD.TailPtr == 0)
  153.         {
  154.         TD.TailPtr     = Timer;
  155.         Timer->Next = Timer;
  156.         }
  157.     else
  158.         {
  159.         Timer->Next     = TD.TailPtr->Next;
  160.         TD.TailPtr->Next   = Timer;
  161.         TD.TailPtr         = Timer;
  162.         }
  163.     }
  164.  
  165. void    DeleteTimer(TIMER *Timer)
  166.     {
  167.     TIMER   *Rover      = TD.TailPtr;
  168.     TIMER   *Previous   = 0;
  169.  
  170.     do  {
  171.         if(Rover->Next == Timer)
  172.             Previous    = Rover;
  173.         else
  174.             Rover       = Rover->Next;
  175.         }   while(Previous == 0);
  176.     if(Previous->Next == Previous)
  177.         TD.TailPtr  = 0;
  178.     else
  179.         {
  180.         if(Previous->Next == TD.TailPtr)
  181.             TD.TailPtr     = Previous;
  182.         Previous->Next  = Previous->Next->Next;
  183.         }
  184.     /* in case it was active...*/
  185.     SetInterval(Timer, 0);
  186.     }
  187.  
  188. WORD FAR PASCAL TimerCallBack(HWND Window,
  189.         WORD MsgNum, WORD WParm, LONG LParm)
  190.     {
  191.     ulong   Time;
  192.     TIMER   *Rover=TD.TailPtr;
  193.     if(!Rover)  return 0;
  194.     do  {
  195.         Rover   = Rover->Next;
  196.         if(Rover->Interval)
  197.             {
  198.             Time    = GetTickCount();
  199.             if(Rover->Interval+Rover->ThisTime
  200.                          <= Time)
  201.                 {
  202.                 Rover->LastTime = Rover->ThisTime;
  203.                 Rover->ThisTime = Time;
  204. #ifdef __cplusplus
  205.                 Rover->Fire();
  206. #else
  207.                 TD.FireFunc(Rover);
  208. #endif
  209.                 }
  210.             }
  211.         } while(Rover != TD.TailPtr);
  212.  
  213.     return 0;
  214.     }
  215.